package com.hq.tomato.ms.context;

import com.hq.tomato.ms.annotation.ReliabilityStrategy;
import com.hq.tomato.ms.strategy.DlqStrategy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.binder.rabbit.properties.RabbitBinderConfigurationProperties;
import org.springframework.cloud.stream.binder.rabbit.properties.RabbitExtendedBindingProperties;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.BindingServiceProperties;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 *
 * @Description: <br>
 * @Project: <br>
 * @CreateDate: Created in 2019-11-20 20:05 <br>
 * @Author: <a href="1026365768@qq.com">qiang.hu</a>
 */
@EnableConfigurationProperties({ RabbitBinderConfigurationProperties.class, RabbitExtendedBindingProperties.class, BindingServiceProperties.class })
public class StrategyApplication implements BeanPostProcessor {
    private static Map<String, Class<? extends DlqStrategy>> CACHE = new ConcurrentHashMap<>();

    @Autowired
    BindingServiceProperties bindingServiceProperties;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass();
        Method[] uniqueDeclaredMethods = ReflectionUtils.getUniqueDeclaredMethods(targetClass);
        for (Method method : uniqueDeclaredMethods) {
            StreamListener streamListener = AnnotatedElementUtils.findMergedAnnotation(method, StreamListener.class);
            ReliabilityStrategy reliabilityStrategy = AnnotatedElementUtils.findMergedAnnotation(method, ReliabilityStrategy.class);

            if (streamListener != null && reliabilityStrategy!=null && !method.isBridge()) {
                String value = streamListener.value();
                Class<? extends DlqStrategy> strategy = reliabilityStrategy.strategy();
                String routeKeyByValue = getRouteKeyByValue(value);
                if(!StringUtils.isEmpty(routeKeyByValue)){
                    CACHE.put(routeKeyByValue,strategy);
                }
            }
        }
        return bean;
    }



    private String getRouteKeyByValue(String value){
        Map<String, BindingProperties> bindings = bindingServiceProperties.getBindings();
        if(!CollectionUtils.isEmpty(bindings)){
            BindingProperties bindingProperties = bindings.get(value);
            if(Objects.nonNull(bindingProperties)){
                String destination = bindingProperties.getDestination();
                if(!StringUtils.isEmpty(destination)){
                    String group = bindingProperties.getGroup();
                    if(!StringUtils.isEmpty(group)){
                        destination = destination+"."+group;
                    }
                    return destination;
                }
            }
        }
        return null;
    }

    /**
     * @Author huqiang
     * @Description //TODO 根据路由key来获取死信策略
     * @Date  2019-11-19
     * @Param routKey
     * @return com.hq.server.constants.DlqStrategyConstants
     */
    public static Class<? extends DlqStrategy> getStrategy(String routKey){
        return CACHE.get(routKey);
    }

}
